package cmq

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/astaxie/beego/logs"
)

//************************通用方法***********************************//

func doCall(url string) (sdkRet, error) {
	var buf sdkRet
	resp, err := http.Get(url)
	if err != nil {
		logs.Error("API request failed: ", err)
		return buf, err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logs.Error("API request failed: ", err)
		return buf, err
	}
	logs.Debug("body %v", string(body))
	err = json.Unmarshal(body, &buf)

	if err != nil {
		logs.Error("json unMarshal failed: ", err)
		return buf, err
	}
	return buf, nil
}

//************************主题相关接口***********************************//

// 创建主题
func (sdk *TencentSDK) AddTopic(topicName string) bool {
	param := make(map[string]string)
	param["topicName"] = topicName
	//if (maxMsgSize)
	//	param["maxMsgSize"]=string(maxMsgSize)

	url := sdk.generatePipeline("CreateTopic", param)
	logs.Debug("request url: ", url)

	ret, err := doCall(url)
	if err != nil {
		logs.Error("docall failed (topicName=%v) :", topicName, err)
		return false
	}
	if ret.Code != 0 {
		logs.Error("AddTopic queue list failed: ", ret.Message)
		return false
	}
	logs.Info("topic [%v]: added!", topicName)
	return true
}

// 获取主题列表
func (sdk *TencentSDK) GetTopicList(topicName string) []TopicRet {

	logs.Info("Get All topic...")
	param := make(map[string]string)
	param["topicName"] = topicName
	url := sdk.generatePipeline("ListTopic", param)
	logs.Debug("request url: ", url)

	ret, err := doCall(url)
	if err != nil {
		logs.Error("docall failed :", err)
		return nil
	}
	if ret.Code != 0 {
		logs.Error("AddTopic queue list failed: ", ret.Message)
		return nil
	}
	topicList := ret.TopicList
	logs.Info("topic [%v]: toplist!")
	return topicList
}

//// 删除主题
func (sdk *TencentSDK) DeleteTopic(topicName string) bool {
	param := make(map[string]string)
	param["topicName"] = topicName
	url := sdk.generatePipeline("DeleteTopic", param)
	logs.Debug("request url: ", url)
	ret, err := doCall(url)
	if err != nil {
		logs.Error("docall failed (topicName=%v) :", topicName, err)
		return false
	}
	if ret.Code != 0 {
		logs.Error("delete queue list failed: ", ret.Message)
		return false
	}
	logs.Info("topic [%v]: deleted!", topicName)
	return true
}

//************************消息相关接口***********************************//

// 发布消息 无差别
func (sdk *TencentSDK) PublishMessage(topicName, message string) bool {
	return _publishMessage(sdk, topicName, message, nil, "")
}

// 发布消息
func _publishMessage(client *TencentSDK, topicName, msg string, tagList []string, routingKey string) bool {
	param := make(map[string]string)
	param["topicName"] = topicName
	param["msgBody"] = msg
	if routingKey != "" {
		param["routingKey"] = routingKey
	}
	if tagList != nil {
		for i, tag := range tagList {
			param["msgTag."+strconv.Itoa(i+1)] = tag
		}
	}

	url := client.generatePipeline("PublishMessage", param)
	logs.Debug("request url: ", url)
	ret, err := doCall(url)
	if err != nil {
		logs.Error("docall failed (topicName=%v) :", topicName, err)
		return false
	}
	if ret.Code != 0 {
		logs.Error("publishMessage queue list failed: ", ret.Message)
		return false
	}
	logs.Info("topic [%v]: _publishMessage!", topicName)
	return true
}

// 批量发布消息 无差别
func (sdk *TencentSDK) BatchPublishMessage(topicName string, msgList []string) bool {
	return _batchPublishMessage(sdk, topicName, msgList, nil, "")

}

// 批量发布消息
func _batchPublishMessage(client *TencentSDK, topicName string, msgList, tagList []string, routingKey string) bool {

	param := make(map[string]string)
	param["topicName"] = topicName
	if routingKey != "" {
		param["routingKey"] = routingKey
	}
	if msgList != nil {
		for i, msg := range msgList {
			param["msgBody."+strconv.Itoa(i+1)] = msg
		}
	}
	if tagList != nil {
		for i, tag := range tagList {
			param["msgTag."+strconv.Itoa(i+1)] = tag
		}
	}

	url := client.generatePipeline("BatchPublishMessage", param)
	logs.Debug("request url: ", url)
	ret, err := doCall(url)
	if err != nil {
		logs.Error("docall failed (topicName=%v) :", topicName, err)
		return false
	}
	if ret.Code != 0 {
		logs.Error("BatchPublishMessage queue list failed: ", ret.Message)
		return false
	}
	logs.Info("topic [%v]: BatchPublishMessage!", topicName)
	return true
}

//************************订阅相关接口***********************************//
const (
	NOTIFY_STRATEGY_DEFAULT = "BACKOFF_RETRY"
	PROTOCOL_HTTP           = "http"
	PROTOCOL_QUEUE          = "queue"

	//notifyContentFormat
	//推送内容的格式。取值：（1）JSON。（2）SIMPLIFIED，即 raw 格式。
	//如果 protocol 是 Queue，则取值必须为 SIMPLIFIED。如果 protocol 是 HTTP，两个值均可以，默认值是 JSON。
	NOTIFY_CONTENT_FORMAT_JSON       = "JSON"
	NOTIFY_CONTENT_FORMAT_SIMPLIFIED = "SIMPLIFIED"
)

// 创建订阅 无差别
/**
endpoint 使用queue 那么 填写 queueName
使用回调地址 那么填写回调地址的路径 注意 必须要是http://的
*/
func (sdk *TencentSDK) CreateSubscribe(topicName, subscriptionName, endpoint, protocol, notifyContentFormat string) bool {
	return _createSubscribe(
		sdk, topicName, subscriptionName, endpoint, protocol, nil, nil,
		NOTIFY_STRATEGY_DEFAULT, notifyContentFormat)
}

// 创建订阅
func _createSubscribe(client *TencentSDK, topicName, subscriptionName, endpoint, protocol string, filterTag []string,
	bindingKey []string, notifyStrategy, notifyContentFormat string) bool {
	param := make(map[string]string)
	if topicName == "" {
		err := fmt.Errorf("createSubscribe failed: topicName is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["topicName"] = topicName

	if subscriptionName == "" {
		err := fmt.Errorf("createSubscribe failed: subscriptionName is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["subscriptionName"] = subscriptionName

	if endpoint == "" {
		err := fmt.Errorf("createSubscribe failed: endpoint is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["endpoint"] = endpoint

	if protocol == "" {
		err := fmt.Errorf("createSubscribe failed: protocal is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["protocol"] = protocol

	if notifyStrategy == "" {
		err := fmt.Errorf("createSubscribe failed: notifyStrategy is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["notifyStrategy"] = notifyStrategy

	if notifyContentFormat == "" {
		err := fmt.Errorf("createSubscribe failed: notifyContentFormat is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["notifyContentFormat"] = notifyContentFormat

	if filterTag != nil {
		for i, tag := range filterTag {
			param["filterTag."+strconv.Itoa(i+1)] = tag
		}
	}

	if bindingKey != nil {
		for i, key := range bindingKey {
			param["bindingKey."+strconv.Itoa(i+1)] = key
		}
	}

	url := client.generatePipeline("Subscribe", param)
	ret, err := doCall(url)

	if err != nil {
		logs.Error("client.call Subscribe failed: %v\n", err.Error())
		return false
	}
	if ret.Code != 0 {
		logs.Error("ret.code Subscribe failed: %v\n")
		return false
	}
	return true
}

// 删除订阅
func (sdk *TencentSDK) DeleteSubscribe(topicName, subscriptionName string) bool {
	param := make(map[string]string)
	if topicName == "" {
		err := fmt.Errorf("createSubscribe failed: topicName is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["topicName"] = topicName

	if subscriptionName == "" {
		err := fmt.Errorf("createSubscribe failed: subscriptionName is empty")
		logs.Error("%v", err.Error())
		return false
	}
	param["subscriptionName"] = subscriptionName
	url := sdk.generatePipeline("Unsubscribe", param)
	ret, err := doCall(url)

	if err != nil {
		logs.Error("client.call Subscribe failed: %v\n", err.Error())
		return false
	}
	if ret.Code != 0 {
		logs.Error("ret.code Subscribe failed: %v\n")
		return false
	}
	return true
}

// 批量获取订阅属性
func (sdk *TencentSDK) ListSubscription(topicName string) []Subscription {

	logs.Info("Get All subscription...")

	param := make(map[string]string)
	param["topicName"] = topicName

	//param["topicName"]=topicName
	url := sdk.generatePipeline("ListTopic", param)
	logs.Debug("request url: ", url)

	ret, err := doCall(url)
	if err != nil {
		logs.Error("docall failed :", err)
		return nil
	}
	if ret.Code != 0 {
		logs.Error("ListSubscription queue list failed: ", ret.Message)
		return nil
	}
	subscriptionList := ret.SubscriptionList
	logs.Info("topic [%v]: toplist!")
	return subscriptionList
}
